package com.orange.core.security.repository;

import cn.hutool.core.util.StrUtil;
import com.orange.core.util.Constants;
import com.orange.core.util.TokenUtil;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.context.HttpRequestResponseHolder;
import org.springframework.security.web.context.SecurityContextRepository;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;

public class DelegatingContextRepository implements SecurityContextRepository {

    private static final Map<Character, DelegatingContextRepository> repositoryMap = new HashMap<>();

    public void registerRepository(Character prefix, DelegatingContextRepository repository) {
        repositoryMap.put(prefix, repository);
    }

    protected SecurityContext loadContext(SecurityContext securityContext, String token) {
        return null;
    }

    @Override
    public SecurityContext loadContext(HttpRequestResponseHolder requestResponseHolder) {
        // 创建空的上下文
        SecurityContext securityContext = SecurityContextHolder.createEmptyContext();
        // 获取token
        String token = requestResponseHolder.getRequest().getHeader(Constants.TOKEN_KEY);
        if (StrUtil.isNotBlank(token)) {
            return Optional.ofNullable(repositoryMap.get(token.charAt(0)))
                    .map(repository -> repository.loadContext(securityContext, token))
                    .orElse(SecurityContextHolder.createEmptyContext());
        }
        return securityContext;
    }

    protected void saveContext(Authentication authentication, HttpServletResponse response) {
    }

    @Override
    public void saveContext(SecurityContext context, HttpServletRequest request, HttpServletResponse response) {
        String token = TokenUtil.getToken(request);
        if (StrUtil.isNotBlank(token)) {
            Optional.ofNullable(repositoryMap.get(token.charAt(0))).ifPresent(repository -> repository.saveContext(context.getAuthentication(), response));
        } else {
            response.setHeader(Constants.TOKEN_KEY, TokenUtil.newToken());
        }
    }

    @Override
    public boolean containsContext(HttpServletRequest request) {
        String token = request.getHeader(Constants.TOKEN_KEY);
        return StrUtil.isNotBlank(token);
    }
}
